package cn.xydpeng.springframework.aop.support.annotation;

import cn.xydpeng.springframework.aop.ClassFilter;
import cn.xydpeng.springframework.aop.MethodMatcher;
import cn.xydpeng.springframework.aop.Pointcut;
import cn.xydpeng.springframework.core.annotation.AnnotationUtils;
import cn.xydpeng.springframework.lang.Nullable;
import cn.xydpeng.springframework.util.Assert;

import java.lang.annotation.Annotation;

/**
 * @author xydpeng
 * @version v1.0
 * @date: 2022/10/21
 * @description:
 */
public class AnnotationMatchingPointcut implements Pointcut {
    private final ClassFilter classFilter;
    private final MethodMatcher methodMatcher;



    /**
     * Create a new AnnotationMatchingPointcut for the given annotation type.
     * @param classAnnotationType the annotation type to look for at the class level
     * @param checkInherited whether to also check the superclasses and interfaces
     * as well as meta-annotations for the annotation type  ---- 注意：checkInherited 是否要检查目标类的父类、接口，以及注解上的注解（组合注解）
     * @see AnnotationClassFilter#AnnotationClassFilter(Class, boolean)
     */
    public AnnotationMatchingPointcut(@Nullable Class<? extends Annotation> classAnnotationType,
                                      @Nullable Class<? extends Annotation> methodAnnotationType, boolean checkInherited) {
        Assert.isTrue(classAnnotationType != null || methodAnnotationType != null, "AnnotationType must not null");
        if (classAnnotationType != null) {
            this.classFilter = new AnnotationClassFilter(classAnnotationType, checkInherited);
        } else {
            this.classFilter = new AnnotationCandidateClassFilter(methodAnnotationType);
        }
        if (methodAnnotationType != null) {
            this.methodMatcher = new AnnotationMethodMatcher(methodAnnotationType, checkInherited);
        } else {
            this.methodMatcher = MethodMatcher.TRUE;
        }
    }

    @Override
    public ClassFilter getClassFilter() {
        return this.classFilter;
    }

    @Override
    public MethodMatcher getMethodMatcher() {
        return this.methodMatcher;
    }


    private static class AnnotationCandidateClassFilter implements ClassFilter {
        private final Class<? extends Annotation> annotationType;

        AnnotationCandidateClassFilter(Class<? extends Annotation> annotationType) {
            this.annotationType = annotationType;
        }

        //annotationType是java原生注解、或者class是非原生类 都返回true
        @Override
        public boolean matches(Class<?> clazz) {
            return AnnotationUtils.isCandidateClass(clazz, this.annotationType);
        }
    }
}
